/*
 *  Copyright 2001-2004 The Apache Software Foundation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package ar.uba.fi.posgrado.economy.model;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import ar.uba.fi.posgrado.academy.model.Body;
import ar.uba.fi.posgrado.academy.model.Course;
import ar.uba.fi.posgrado.common.model.AbstractDomainObject;
import ar.uba.fi.posgrado.common.model.Student;

/**
 * Deuda que tiene un Alumno, con la secretaria de Posgrado de FIUBA,
 * correspondiente a uno o mas cursos de Posgrado.<br>
 * <br>
 * 
 * Cuando se crea una deuda se crea con {@link #balance} =
 * {@link #originalBalance}.<br>
 * 
 * En caso de que saldo de la deuda sea menor a la deuda original no se
 * aplicaran descuentos ni beneficios.<br>
 * Esto es debido a que se aplicaron previamente, pero quedo un saldo, el cual a
 * la hora de "saldarlo", ya no son aplicables los descuentos y beneficios.<br>
 * 
 * @author nicolas.gonzalez
 * @author pablo.tortorella
 * @see AbstractDomainObject
 */
@Entity
@Table(name = "DEUDA")
@SuppressWarnings("serial")
public class Debt extends AbstractDomainObject {

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_ALUMNO")
	private Student student;

	@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
	@JoinColumn(name = "ID_CLIENTE")
	private Customer customer;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_CURSO")
	private Course course;

	@Column(name = "VIGENCIA_DESDE")
	private Date validityFrom;

	@Column(name = "VENCIMIENTO")
	private Date expiry;

	@Column(name = "SALDO_DEUDA")
	private Double balance;

	@Column(name = "DEUDA_ORIGINAL")
	private Double originalBalance;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_TIPO_CONCEPTO")
	private DebtType debtType;

	@Column(name = "ESTADO")
	private DebtStatus debtStatus; // Cancelled, Paid, Balanced, Active

	@Column(name = "MOTIVO", length = 255, nullable = true)
	private String reason;

	@OneToMany(fetch = FetchType.LAZY)
	@JoinTable(name = "DEUDA_BENEFICIO", joinColumns = @JoinColumn(name = "ID_DEUDA", referencedColumnName = "ID"), inverseJoinColumns = @JoinColumn(name = "ID_BENEFICIO", referencedColumnName = "ID"))
	private Set<Benefit> benefits = new HashSet<Benefit>();

	@OneToMany(fetch = FetchType.LAZY)
	@JoinTable(name = "DEUDA_DESCUENTO", joinColumns = @JoinColumn(name = "ID_DEUDA", referencedColumnName = "ID"), inverseJoinColumns = @JoinColumn(name = "ID_DESCUENTO", referencedColumnName = "ID"))
	private Set<Discount> discounts = new HashSet<Discount>();

	// Este se saca del curso. Es para agilizar busquedas basicamente... El
	// usuario NUNCA ve esto ni lo selecciona
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_ENTE")
	private Body body;

	public Debt() {
	}

	/**
	 * @param student
	 * @param customer
	 * @param course
	 * @param validityFrom
	 * @param expiry
	 * @param balance
	 * @param originalBalance
	 * @param debtType
	 * @param debtStatus
	 * @param reason
	 * @param benefits
	 * @param discounts
	 */
	public Debt(Student student, Customer customer, Course course,
			Date validityFrom, Date expiry, Double balance,
			Double originalBalance, DebtType debtType, DebtStatus debtStatus,
			String reason, Set<Benefit> benefits, Set<Discount> discounts) {
		this.student = student;
		this.customer = customer;
		this.course = course;
		this.validityFrom = validityFrom;
		this.expiry = expiry;
		this.balance = balance;
		this.originalBalance = originalBalance;
		this.debtType = debtType;
		this.debtStatus = debtStatus;
		this.reason = reason;
		this.benefits = benefits;
		this.discounts = discounts;
	}

	/**
	 * @see DebtStatus#appliesAccountModification()
	 */
	public boolean appliesAccountModification() {
		return this.debtStatus.appliesAccountModification();
	}

	/**
	 * @see ar.uba.fi.posgrado.common.model.AbstractDomainObject#getExcludedFields()
	 */
	@Override
	public String[] getExcludedFields() {
		return new String[] { "balance", "debtType", "student", "customer",
				"course", "validityFrom", "expiry", "originalBalance",
				"debtStatus", "reason", "benefits", "discounts", "body" };
	}

	public DebtType getDebtType() {
		return debtType;
	}

	public void setDebtType(DebtType concepto) {
		this.debtType = concepto;
	}

	public Student getStudent() {
		return student;
	}

	public void setStudent(Student student) {
		this.student = student;
	}

	public DebtStatus getDebtStatus() {
		return debtStatus;
	}

	public void setDebtStatus(DebtStatus estado) {
		this.debtStatus = estado;
	}

	/**
	 * @return the validityFrom
	 */
	public Date getValidityFrom() {
		return this.validityFrom;
	}

	/**
	 * @param validityFrom
	 *            the validityFrom to set
	 */
	public void setValidityFrom(Date validityFrom) {
		this.validityFrom = validityFrom;
	}

	/**
	 * @return the expiry
	 */
	public Date getExpiry() {
		return this.expiry;
	}

	/**
	 * @param expiry
	 *            the expiry to set
	 */
	public void setExpiry(Date expiry) {
		this.expiry = expiry;
	}

	/**
	 * @return the balance
	 */
	public Double getBalance() {
		return this.balance;
	}

	/**
	 * @param balance
	 *            the balance to set
	 */
	public void setBalance(Double balance) {
		this.balance = balance;
	}

	/**
	 * @return the originalBalance
	 */
	public Double getOriginalBalance() {
		return this.originalBalance;
	}

	/**
	 * @param originalBalance
	 *            the originalBalance to set
	 */
	public void setOriginalBalance(Double originalBalance) {
		this.originalBalance = originalBalance;
	}

	/**
	 * @return the benefits
	 */
	public Set<Benefit> getBenefits() {
		return this.benefits;
	}

	/**
	 * @param benefits
	 *            the benefits to set
	 */
	public void setBenefits(Set<Benefit> benefits) {
		this.benefits = benefits;
	}

	/**
	 * @return the discounts
	 */
	public Set<Discount> getDiscounts() {
		return this.discounts;
	}

	/**
	 * @param discounts
	 *            the discounts to set
	 */
	public void setDiscounts(Set<Discount> discounts) {
		this.discounts = discounts;
	}

	/**
	 * @return the reason
	 */
	public String getReason() {
		return this.reason;
	}

	/**
	 * @param reason
	 *            the reason to set
	 */
	public void setReason(String reason) {
		this.reason = reason;
	}

	/**
	 * @return the customer
	 */
	public Customer getCustomer() {
		return this.customer;
	}

	/**
	 * @param customer
	 *            the customer to set
	 */
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

	/**
	 * @return the course
	 */
	public Course getCourse() {
		return this.course;
	}

	/**
	 * @param course
	 *            the course to set
	 */
	public void setCourse(Course course) {
		this.course = course;
	}

	/**
	 * @return the body
	 */
	public Body getBody() {
		return body;
	}

	/**
	 * @param body
	 *            the body to set
	 */
	public void setBody(Body body) {
		this.body = body;
	}

	public String getDiscountsAndBenefitsSummary() {
		StringBuffer response = new StringBuffer("Benef:");
		response.append(this.getBenefitsPercentaje()).append("%|$").append(
				this.getBenefitsValue()).append(" Desc: ").append(
				this.getDiscountsPercentage()).append("%|$").append(
				this.getDiscountsValue());
		return response.toString();
	}

	private Double getBenefitsPercentaje() {
		Double response = new Double(0);

		for (Benefit benefit : this.benefits) {
			response += benefit.getPercentage();
		}

		return response;
	}

	private Double getBenefitsValue() {
		Double response = new Double(0);

		for (Benefit benefit : this.benefits) {
			response += benefit.getValue();
		}

		return response;
	}

	private Double getDiscountsPercentage() {
		Double response = new Double(0);

		for (Discount discount : this.discounts) {
			response += discount.getPercentage();
		}

		return response;
	}

	private Double getDiscountsValue() {
		Double response = new Double(0);

		for (Discount discount : this.discounts) {
			response += discount.getValue();
		}

		return response;
	}

}
